package cn.getech.data.development.utils;

import cn.getech.data.development.constant.ApplyStatusEnum;
import cn.getech.data.development.constant.PermissionTypeEnum;
import cn.getech.data.development.constant.StoreTableType;
import cn.getech.data.development.constant.YesOrNoEnum;
import cn.getech.data.development.entity.TableFieldInfo;
import cn.getech.data.development.entity.dataMap.DataApplication;
import cn.getech.data.development.entity.dataMap.DataApplicationExample;
import cn.getech.data.development.entity.dataMap.DataApplicationField;
import cn.getech.data.development.entity.dataMap.DataApplicationFieldExample;
import cn.getech.data.development.entity.flink.BdpRealTableField;
import cn.getech.data.development.entity.permission.SysRoleDataPermission;
import cn.getech.data.development.entity.permission.SysRoleDataPermissionExample;
import cn.getech.data.development.entity.permission.SysTenantDataPermission;
import cn.getech.data.development.entity.permission.SysTenantDataPermissionExample;
import cn.getech.data.development.mapper.TableFieldInfoMapper;
import cn.getech.data.development.mapper.dataMap.DataApplicationFieldMapper;
import cn.getech.data.development.mapper.dataMap.DataApplicationMapper;
import cn.getech.data.development.mapper.flink.BdpRealTableFieldMapper;
import cn.getech.data.development.mapper.permission.SysRoleDataPermissionMapper;
import cn.getech.data.development.mapper.permission.SysTenantDataPermissionMapper;
import cn.getech.data.development.utils.spring.SpringContextUtil;
import cn.getech.system.center.service.SysUserRoleService;
import cn.getech.system.center.utils.ShiroUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @description: 数据权限公共处理类
 * @author: wangzhaowen：kiss
 * @create: 2020/8/3 11:07
 * @version: 2020/8/3
 **/
public class DataPermissionUtil {

    private static Logger logger = LoggerFactory.getLogger(DataPermissionUtil.class);
    private static DataApplicationMapper dataDao = SpringContextUtil.getBean(DataApplicationMapper.class);
    private static DataApplicationFieldMapper dataApplicationFieldMapper = SpringContextUtil.getBean(DataApplicationFieldMapper.class);
    private static SysRoleDataPermissionMapper permissionDao = SpringContextUtil.getBean(SysRoleDataPermissionMapper.class);
    private static SysTenantDataPermissionMapper tenantPermissionDao = SpringContextUtil.getBean(SysTenantDataPermissionMapper.class);
    private static TableFieldInfoMapper tableFieldInfoMapper = SpringContextUtil.getBean(TableFieldInfoMapper.class);
    private static BdpRealTableFieldMapper bdpRealTableFieldMapper= SpringContextUtil.getBean(BdpRealTableFieldMapper.class);;
    private static SysUserRoleService sysUserRoleService =  SpringContextUtil.getBean(SysUserRoleService.class);


    /**
     * 查询拥有权限的数据id
     *
     * @param userId    用户id
     * @param dataType  数据类型 {@link PermissionTypeEnum#RESOURCE}
     * @param operation 操作类型 {@link PermissionTypeEnum#QUERY}
     */
    public static List<Integer> getDataIds(Integer userId, Integer dataType, Integer operation) {
        List<Integer> ids = new ArrayList<>();
        Integer tenantId = ShiroUtils.getTenantId();
        //如果是租户管理员，则需要查询到这个租户管理员下的角色
        boolean admin = DataPermissionUtil.isAdmin(userId);
        List<Long> roleIds = new ArrayList<>();
        if(admin){
            if (tenantId != null) {
                ids.addAll(tenantPermissionDao.getDataIdsTenantId(tenantId,dataType));
            }
        }else{
            roleIds = sysUserRoleService.queryChildrenRoleIdList(Long.valueOf(userId), tenantId);
        }
        if (CollectionUtils.isNotEmpty(roleIds)) {
            SysRoleDataPermissionExample param = new SysRoleDataPermissionExample();
            SysRoleDataPermissionExample.Criteria criteria = param.createCriteria();
            criteria.andRoleIdIn(roleIds).andDataTypeEqualTo(dataType);
            if (PermissionTypeEnum.QUERY.getType().equals(operation)) {
                criteria.andQueryEqualTo(YesOrNoEnum.YES.getValue());
            } else if (PermissionTypeEnum.UPDATE.getType().equals(operation)) {
                criteria.andUpdateEqualTo(YesOrNoEnum.YES.getValue());
            } else if (PermissionTypeEnum.DELETE.getType().equals(operation)) {
                criteria.andDeleteEqualTo(YesOrNoEnum.YES.getValue());
            } else if (PermissionTypeEnum.CREATE.getType().equals(operation)) {
                criteria.andCreateEqualTo(YesOrNoEnum.YES.getValue());
            } else if (PermissionTypeEnum.ASSIGN.getType().equals(operation)) {
                criteria.andAssignEqualTo(YesOrNoEnum.YES.getValue());
            } else if (PermissionTypeEnum.EXPORT.getType().equals(operation)) {
                criteria.andExportEqualTo(YesOrNoEnum.YES.getValue());
            } else if (PermissionTypeEnum.DECRYPT.getType().equals(operation)) {
                criteria.andDecryptEqualTo(YesOrNoEnum.YES.getValue());
            }else if (PermissionTypeEnum.WRITE.getType().equals(operation)) {
                criteria.andWriteEqualTo(YesOrNoEnum.YES.getValue());
            }
            List<SysRoleDataPermission> list = permissionDao.selectByExample(param);
            if (CollectionUtils.isNotEmpty(list)) {
                for (SysRoleDataPermission permission : list) {
                    ids.add(permission.getDataId());
                }
            }
            /**
             * 数据仓库 获取通过权限申请的的数据id
             */
            if (PermissionTypeEnum.STORE.getType().equals(dataType)) {//数据长裤数据
                List<Integer> appDataIds = getApplyDataIds(Long.parseLong(userId.toString()), operation);
                if (CollectionUtils.isNotEmpty(appDataIds)) {
                    ids.addAll(appDataIds);
                }
                if (PermissionTypeEnum.QUERY.getType().equals(operation)) {
                    //拥有新增字段的权限，也有表查询的权限
                    ids.addAll(getApplyDataIds(Long.parseLong(userId.toString()), PermissionTypeEnum.ASSIGN.getType()));

                    //拥有某字段的权限，也有表查询的权限
                    ids.addAll(getApplyDataIds(Long.parseLong(userId.toString()), PermissionTypeEnum.DECRYPT.getType()));
                }
            }
            /**
             * 实时表 获取通过权限申请的的数据id
             */
            if (PermissionTypeEnum.REAL_TABLE.getType().equals(dataType)) {
                List<Integer> appDataIds = getApplyRealTableDataIds(Long.parseLong(userId.toString()), operation);
                if (CollectionUtils.isNotEmpty(appDataIds)) {
                    ids.addAll(appDataIds);
                }
                if (PermissionTypeEnum.QUERY.getType().equals(operation)) {
                    //拥有新增字段的权限，也有表查询的权限
                    ids.addAll(getApplyRealTableDataIds(Long.parseLong(userId.toString()), PermissionTypeEnum.ASSIGN.getType()));

                    //拥有某字段的权限，也有表查询的权限
                    ids.addAll(getApplyRealTableDataIds(Long.parseLong(userId.toString()), PermissionTypeEnum.DECRYPT.getType()));
                }
            }
        } else {
            logger.warn("当前登录用户id：{}未分配角色信息：", userId);
        }

        if (tenantId != null) {
            if(admin){
                //如果是租户管理员，才需要给这个权限
                SysTenantDataPermissionExample param = new SysTenantDataPermissionExample();
                SysTenantDataPermissionExample.Criteria criteria = param.createCriteria();
                criteria.andTenantIdEqualTo(tenantId).andDataTypeEqualTo(dataType);
                if (PermissionTypeEnum.QUERY.getType().equals(operation)) {
                    criteria.andQueryEqualTo(YesOrNoEnum.YES.getValue());
                } else if (PermissionTypeEnum.UPDATE.getType().equals(operation)) {
                    criteria.andUpdateEqualTo(YesOrNoEnum.YES.getValue());
                } else if (PermissionTypeEnum.DELETE.getType().equals(operation)) {
                    criteria.andDeleteEqualTo(YesOrNoEnum.YES.getValue());
                } else if (PermissionTypeEnum.CREATE.getType().equals(operation)) {
                    criteria.andCreateEqualTo(YesOrNoEnum.YES.getValue());
                } else if (PermissionTypeEnum.ASSIGN.getType().equals(operation)) {
                    criteria.andAssignEqualTo(YesOrNoEnum.YES.getValue());
                } else if (PermissionTypeEnum.EXPORT.getType().equals(operation)) {
                    criteria.andExportEqualTo(YesOrNoEnum.YES.getValue());
                } else if (PermissionTypeEnum.DECRYPT.getType().equals(operation)) {
                    criteria.andDecryptEqualTo(YesOrNoEnum.YES.getValue());
                }else if (PermissionTypeEnum.WRITE.getType().equals(operation)) {
                    criteria.andWriteEqualTo(YesOrNoEnum.YES.getValue());
                }
                List<SysTenantDataPermission> list = tenantPermissionDao.selectByExample(param);
                if (CollectionUtils.isNotEmpty(list)) {
                    for (SysTenantDataPermission permission : list) {
                        ids.add(permission.getDataId());
                    }
                }
            }

        }
        return ids;
    }

    /**
     * 获取权限申请的数据id
     *
     * @param userId    用户id
     * @param operation 操作类型
     */
    public static List<Integer> getApplyDataIds(Long userId, Integer operation) {
        DataApplicationExample param = new DataApplicationExample();
        DataApplicationExample.Criteria criteria = param.createCriteria();
        criteria.andUserIdEqualTo(userId)
                .andApplyTypeEqualTo(1)
                .andApplyStatusEqualTo(ApplyStatusEnum.PASS.getType())
                .andEffectiveDeadlineGreaterThan(new Date());//有效期之内的数据
        return getDataList(operation, param, criteria);
    }

    private static List<Integer> getDataList(Integer operation, DataApplicationExample param, DataApplicationExample.Criteria criteria) {
        if (PermissionTypeEnum.QUERY.getType().equals(operation)) {
            criteria.andQueryEqualTo(YesOrNoEnum.YES.getValue());
        } else if (PermissionTypeEnum.UPDATE.getType().equals(operation)) {
            criteria.andUpdateEqualTo(YesOrNoEnum.YES.getValue());
        } else if (PermissionTypeEnum.DELETE.getType().equals(operation)) {
            criteria.andDeleteEqualTo(YesOrNoEnum.YES.getValue());
        } else if (PermissionTypeEnum.EXPORT.getType().equals(operation)) {
            criteria.andExportEqualTo(YesOrNoEnum.YES.getValue());
        } else if (PermissionTypeEnum.DECRYPT.getType().equals(operation)) {
            criteria.andDecryptEqualTo(YesOrNoEnum.YES.getValue());
        }else{
            return new ArrayList<>();
        }
        List<DataApplication> list = dataDao.selectByExample(param);
        if (CollectionUtils.isNotEmpty(list)) {
            return list.stream().filter(s -> s.getTableId() != null)
                    .map(DataApplication::getTableId).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }


    /**
     * 获取权限申请的实时表数据id
     *
     * @param userId    用户id
     * @param operation 操作类型
     */
    public static List<Integer> getApplyRealTableDataIds(Long userId, Integer operation) {
        DataApplicationExample param = new DataApplicationExample();
        DataApplicationExample.Criteria criteria = param.createCriteria();
        criteria.andUserIdEqualTo(userId)
                .andApplyTypeEqualTo(2)
                .andApplyStatusEqualTo(ApplyStatusEnum.PASS.getType())
                .andEffectiveDeadlineGreaterThan(new Date());//有效期之内的数据
        return getDataList(operation, param, criteria);
    }
    /**
     * 查询拥有权限的数据id
     *
     * @param dataType  数据类型 {@link PermissionTypeEnum#RESOURCE}
     * @param operation 操作类型 {@link PermissionTypeEnum#QUERY}
     */
    public static List<Integer> getDataIds(Integer dataType, Integer operation) {
        Integer userId = ShiroUtils.getUserId().intValue();
        return getDataIds(userId, dataType, operation);
    }

    /**
     * 添加权限过滤参数
     *
     * @param params    参数Map
     * @param dataType  数据类型 {@link PermissionTypeEnum#RESOURCE}
     * @param operation 操作类型 {@link PermissionTypeEnum#QUERY}
     */
    public static void putDataFilter(Map<String, Object> params,

                                     Integer dataType,
                                     Integer operation
    ) {
        Integer userId = ShiroUtils.getUserId().intValue();
        params.put("create_per", userId);
        params.put("tenantId", ShiroUtils.getTenantId());
        List<Integer> ids = getDataIds(userId, dataType, operation);
        if (CollectionUtils.isNotEmpty(ids)) {
            params.put("ids", ids);
        } else {
            ids.add(-1);//无权限查询-1的数据
            params.put("ids", ids);
        }
    }
    public static boolean isAdmin(Integer userId) {
        Integer adminCount = permissionDao.queryAdmin(userId,ShiroUtils.getTenantId());
        if (adminCount!=null&&adminCount>0
            //  || RoleTypeEnum.Admin.getCode().equals(roleType)
        ) {//超级管理员  不需要权限过滤
            return true;
        } else {
            return false;
        }
    }

    public static boolean isMainTenantAdmin(Integer userId,Integer tenantId) {
        Integer adminCount = permissionDao.queryAdmin(userId,tenantId);
        if (adminCount!=null&&adminCount>0
            //  || RoleTypeEnum.Admin.getCode().equals(roleType)
        ) {//超级管理员  不需要权限过滤
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取新增字段  数据权限
     * @param tableId 表id
     * @param userId  用户id
     */
    public static List<Integer> getCreateFiledIds(Integer tableId, Long userId,Integer tableType) {
        DataApplicationExample param = new DataApplicationExample();
        DataApplicationExample.Criteria criteria = param.createCriteria();
        criteria.andUserIdEqualTo(userId)
                .andApplyTypeEqualTo(tableType)
                .andApplyStatusEqualTo(ApplyStatusEnum.PASS.getType())
                .andEffectiveDeadlineGreaterThan(new Date())//有效期之内的数据
                .andTableIdEqualTo(tableId)
                .andAssignEqualTo(YesOrNoEnum.YES.getValue());
        List<DataApplication> list = dataDao.selectByExample(param);
        List<Integer> haveIds=new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            for (DataApplication dataApplication : list) {
                Date endDate = dataApplication.getEffectiveDeadline();
                Date startDate = dataApplication.getHandleTime();
                if (StoreTableType.OFFLINE.getCode().equals(tableType)) {
                    QueryWrapper<TableFieldInfo> wrapper = new QueryWrapper<>();
                    wrapper.eq("table_id", tableId);
                    wrapper.ge(startDate != null, "create_time", startDate)
                            .le(endDate != null, "create_time", endDate);
                    List<TableFieldInfo> fieldList = tableFieldInfoMapper.selectList(wrapper);
                    if (CollectionUtils.isNotEmpty(list)) {
                        haveIds.addAll(fieldList.stream().map(TableFieldInfo::getId).collect(Collectors.toList()));
                    }
                }else
                {
                    QueryWrapper<BdpRealTableField> wrapper = new QueryWrapper<>();
                    wrapper.eq("table_id", tableId);
                    wrapper.ge(startDate != null, "create_time", startDate)
                            .le(endDate != null, "create_time", endDate);
                    List<BdpRealTableField> fieldList = bdpRealTableFieldMapper.selectList(wrapper);
                    if (CollectionUtils.isNotEmpty(list)) {
                        haveIds.addAll(fieldList.stream().map(BdpRealTableField::getId).collect(Collectors.toList()));
                    }
                }

            }

        }
        //添加申请的字段权限
        haveIds.addAll(getFiledIds(tableId, userId,tableType));
        if (CollectionUtils.isNotEmpty(haveIds)) {
            return  haveIds;
        }
        return new ArrayList<>();
    }

    /**
     * 获取申请的字段权限 字段id
     * @param tableId 表id
     * @param userId  用户id
     * @param tableType
     */
    public static List<Integer> getFiledIds(Integer tableId, Long userId, Integer tableType) {
        DataApplicationExample param = new DataApplicationExample();
        DataApplicationExample.Criteria criteria = param.createCriteria();
        criteria.andUserIdEqualTo(userId)
                .andApplyTypeEqualTo(tableType)
                .andApplyStatusEqualTo(ApplyStatusEnum.PASS.getType())
                .andEffectiveDeadlineGreaterThan(new Date())//有效期之内的数据
                .andTableIdEqualTo(tableId)
                .andQueryEqualTo(YesOrNoEnum.NO.getValue());
        List<DataApplication> list = dataDao.selectByExample(param);
        if (CollectionUtils.isNotEmpty(list)) {
            for (DataApplication dataApplication : list) {
                DataApplicationFieldExample example = new DataApplicationFieldExample();
                example.createCriteria().andApplyIdEqualTo(dataApplication.getId());
                List<DataApplicationField> fieldList = dataApplicationFieldMapper.selectByExample(example);
                if (CollectionUtils.isNotEmpty(fieldList)) {
                    return fieldList.stream().map(s -> s.getFiledId().intValue()).collect(Collectors.toList());
                }
            }
        }
        return new ArrayList<>();
    }

}
